/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package net.worlds.ui.edge;

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import net.worlds.Main;
import net.worlds.Util;
import net.worlds.ui.UI;

/**
 *
 * @author Jacob Morgan
 */
public class EComponent {
    private final Map<Integer, ArrayList<EComponent>> children = Collections.synchronizedMap(new HashMap<Integer, ArrayList<EComponent>>(8));
    protected int width;
    protected int height;
    public int x;
    public int y;
    protected EComponent parent;
    protected static FontMetrics defaultFontMetrics = null;
    protected static int lineHeight;
    protected int layer = -1;
    protected boolean isPrimary = false;
    protected Graphics2D g;
    public boolean mouseOver;
    public boolean clickThrough = false;
    protected boolean beingDragged = false;
    protected boolean fixed = true;
    protected boolean visible = true;
    public boolean enabled = true;
    public String tooltip = null;
    public int tooltipWidth;
    public int tooltipHeight;
    protected static final Color tooltipColor = new Color(123, 128, 154);
    protected static final Color tooltipBorderColor = new Color(28, 36, 78);
    public EComponent()
    {
        for(int i = 0; i < 8; i++)
            children.put(i, new ArrayList<EComponent>(EDGESettings.maxComponents));
    }
    public void setTooltip(String tt)
    {
        tooltip = tt;
        if(tt != null)
        {
            Rectangle2D bounds = EDGESettings.defaultFont.getStringBounds(tt, Util.fontRendererContext);
            tooltipWidth = (int) bounds.getWidth();
            tooltipHeight = (int) bounds.getHeight();
        }
    }
    public void setEnabled(boolean v)
    {
        enabled = v;
    }
    public void setFixed(boolean v)
    {
        fixed = v;
    }
    public void addChild(int layer, EComponent c)
    {
        synchronized(children)
        {
            c.setLayer(layer);
            c.setParent(this);
            children.get(layer).add(c);
        }
    }
    public void removeChild(EComponent c)
    {
        synchronized(children)
        {
            children.get(c.layer).remove(c);
        }
    }
    public void setParent(EComponent c)
    {
        parent = c;
    }
    public EComponent[] getChildren()
    {
        ArrayList<EComponent> allChildren = new ArrayList<EComponent>(EDGESettings.maxComponents);
        synchronized(children)
        {
            for(int i = 0; i < 8; i++)
            {
                ArrayList<EComponent> cLayer = children.get(i);
                allChildren.addAll(cLayer);
            }
        }
        EComponent[] e = new EComponent[allChildren.size()];
        allChildren.toArray(e);
        return e;
    }
    public boolean hasChild(int layer, EComponent c)
    {
        return children.get(layer).contains(c);
    }
    public EComponent[] getChildren(int layer)
    {
        EComponent[] e = new EComponent[children.get(layer).size()];
        synchronized(children)
        {
            children.get(layer).toArray(e);
        }
        return e;
    }
    public int getX()
    {
        if(isPrimary || parent == null)
            return 0;
        else
            return x + parent.getX();
    }
    public int getY()
    {
        if(isPrimary || parent == null)
            return 0;
        else
            return y + parent.getY();
    }
    public void setX(int v)
    {
        x = v;
    }
    public void setY(int v)
    {
        this.y = v;
    }
    public void setWidth(int w)
    {
        width = w;
    }
    public void setHeight(int h)
    {
        height = h;
    }
    public int getWidth()
    {
        return width;
    }
    public int getHeight()
    {
        return height;
    }
    public void setLayer(int l)
    {
        if(parent == null)
            layer = l;
        else
        {
            synchronized(parent.children)
            {
                if(parent != null)
                    parent.children.get(layer).remove(this);
                layer = l;
                if(parent != null)
                    parent.children.get(layer).add(this);
            }
        }
    }
    public int getLayer()
    {
        return layer;
    }
    public boolean testPoint(int px, int py)
    {
        //if(this instanceof EToggleButton)
        return enabled && px > getX() && py > getY() && px < getX() + getWidth() && py < getY() + getHeight();
    }
    public void putOnTop()
    {
        if(parent != null)
            for(EComponent c : parent.getChildren())
            {
                if(c.layer > layer)
                {
                    int oldLayer = layer;
                    setLayer(c.layer);
                    c.setLayer(oldLayer);
                }
            }
    }
    public void render(Graphics2D g)
    {
        if(defaultFontMetrics == null)
        {
            defaultFontMetrics = g.getFontMetrics();
            lineHeight = (int) defaultFontMetrics.getStringBounds("X", g).getHeight();
        }
        renderChildren(g);
    }
    protected void renderChildren(Graphics2D g)
    {
        this.g = g;
        synchronized(children)
        {
            for(int i : children.keySet())
            {
                for(EComponent c : children.get(i))
                {
                    if(c instanceof EMenu && c.visible)
                        c = c;
                    if(c.visible)
                        c.render(g);
                }
            }
        }
    }
    public void click()
    {
        mouseDown(1, 0, 0);
    }
    public boolean mouseDown(int b, int localX, int localY)
    {
        for(EComponent c : getChildren())
        {
            if(c.testPoint(localX, localY))
            {
                c.mouseDown(b, localX, localY);
                if(!c.clickThrough)
                    return false;
            }
        }
        mousePressed();
        return true;
    }
    public boolean mouseClick(int b, int localX, int localY)
    {
        for(EComponent c : getChildren())
        {
            if(c.testPoint(localX, localY))
            {
                c.mouseClick(b, localX, localY);
                if(!c.clickThrough)
                    return false;
            }
        }
        return true;
    }
    public boolean mouseUp(int b, int localX, int localY)
    {
        for(EComponent c : getChildren())
        {
            if(c.testPoint(localX, localY))
            {
                c.mouseUp(b, localX, localY);
                return false;
            }
        }
        mouseReleased();
        return true;
    }
    public boolean mouseMove(int x, int y, int px, int py)
    {
        for(EComponent c : getChildren())
        {
            if(c.testPoint(x, y))
            {
                if(c.mouseMove(x, y, px, py))
                    EDGESettings.main.setMouseComponent(c);
                return false;
            }
        }
        return true;
    }
    public void mouseOver()
    {
        if(!clickThrough && !UI.mouseOverUI)
        {
            UI.mouseOverUI = true;
            UI.mouseOverUI();
            Main.mouseOverUI();
        }
    }
    public void mouseOff()
    {

    }
    public void mousePressed()
    {

    }
    public void mouseReleased()
    {
        
    }
    public boolean mouseDrag(int x, int y, int px, int py)
    {
        for(EComponent c : getChildren())
        {
            if(c.testPoint(x, y))
            {
                EDGESettings.main.setMouseComponent(c);
                return false;
            }
        }
        return true;
    }
    public void remove()
    {
        if(parent != null)
            parent.removeChild(this);
    }
    protected void drawText(Graphics g, Font font, String t, Color c, int x, int y)
    {
        g.setFont(font);
        g.setColor(c);
        g.drawString(t, x, y);
    }
    public void destructor()
    {
        
    }
    public void setVisible(boolean v)
    {
        visible = v;
        synchronized(children)
        {
            for(int i = 0; i < 8; i++)
            for(EComponent c : children.get(i))
            {
                c.setVisible(v);
            }
        }
    }
}
